﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using DynORM.TypeMappingSubsystem;

namespace DynORM.Interfaces
{
    public class BLLComparison
    {
        private readonly MemberInfo member;
        private readonly BLLComparisonOperator condition;
        private readonly object value;

        

        public BLLComparison(MemberInfo member, BLLComparisonOperator condition, object value)
        {
            //operators depends on operand's type. 
            //only equal and unequal don't depend on operand type (most of the data type interprent it according to its semantics)
            Type membersType;
            if (member is PropertyInfo)
                membersType = ((PropertyInfo)member).PropertyType;
            else if (member is FieldInfo)
                membersType = ((FieldInfo)member).FieldType;
            else
                throw new Exception("Class member denoted in BLLComparison should be either property or field.");

            if (Types.GetCLRCompatibleTypes(membersType).Union(Types.GetCLRCompatibleTypes(value.GetType())).Count() == 0)
                throw new Exception("Left and right operands in comparison have incompatible types.");

            if (!Types.GetCLRLessGreaterTypes().Contains(membersType)
                && (condition == BLLComparisonOperator.Less || condition == BLLComparisonOperator.LessOrEqual || condition == BLLComparisonOperator.Greater || condition == BLLComparisonOperator.GreaterOrEqual))
                throw new Exception("Incompatible operand type and operator.");

            this.member = member;
            this.condition = condition;
            this.value = value;
        }

        public MemberInfo Member
        {
            get
            {
                return this.member;
            }
        }

        public BLLComparisonOperator Condition
        {
            get
            {
                return this.condition;
            }
        }

        public object Value
        {
            get
            {
                return this.value;
            }
        }

        #region Value-based equality semantics implementation
        public override bool Equals(object obj)
        {
            BLLComparison that;
            if (obj is BLLComparison)
                that = (BLLComparison)obj;
            else
                return false;

            if (String.Compare(that.Member.Name, this.member.Name, StringComparison.OrdinalIgnoreCase) == 0 && that.Condition == this.condition && this.Value.Equals(that.value))
                return true;
            else
                return false;
        }

        public override int GetHashCode()
        {
            return this.Member.GetHashCode();
        }

        public static bool operator ==(BLLComparison obj1, BLLComparison obj2)
        {
            if (!Object.ReferenceEquals(obj1, null))
                return obj1.Equals(obj2);
            else
                return false;
        }

        public static bool operator !=(BLLComparison obj1, BLLComparison obj2)
        {
            if (!Object.ReferenceEquals(obj1, null))
                return !obj1.Equals(obj2);
            else
                return false;
        }

        #endregion
    }
}
